package org.salatec.tapestry4e.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

public class T5Component implements Comparable<T5Component> {
	public static final String COMPONENT_ELEMENT = "Component";

	private static final String NAME_ATTR = "name";
	private static final String PARAMETERS_EL = "parameters";
	private static final String PARAMETER_EL = "parameter";
	private static final String PROPERTIES_EL = "properties";
	private static final String PROPERTY_EL = "property";

	private String name;
	private List<String> properties;
	private List<String> parameters;

	@SuppressWarnings("unchecked")
	public T5Component(ICompilationUnit unit) throws JavaModelException {

		IType type = unit.getTypes()[0];

		if (type.isClass() && !type.isInterface()) {
			this.setName(type.getElementName());
			this.setProperties(findAnnotationInClass("Property", type));
			this.setParameters(findAnnotationInClass("Parameter", type));
		}

	}

	private List<String> findAnnotationInClass(String annotation, IType cls)
			throws JavaModelException {
		IField[] fields = cls.getFields();
		List<String> result = new ArrayList<String>();
		for (IField field : fields) {
			IAnnotation ann = field.getAnnotation(annotation);
			boolean exists = ann.exists();
			if (exists) {
				result.add(field.getElementName());
			}
		}
		return result;
	}

	public T5Component() {

	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public List<String> getProperties() {
		return properties;
	}

	public void setProperties(List<String> properties) {
		this.properties = properties;
	}

	public List<String> getParameters() {
		return parameters;
	}

	public void setParameters(List<String> parameters) {
		this.parameters = parameters;
	}

	/**
	 * Generates the XML string format used by the component.
	 */
	public String toString() {
		if (this.name != null || "".equalsIgnoreCase(name)) {
			StringBuilder builder = new StringBuilder();
			builder.append("<Component name=\"" + name + "\">");

			if (parameters != null && parameters.size() > 0) {
				builder.append("<parameters>");
				Iterator<String> it = parameters.iterator();
				while (it.hasNext()) {
					builder.append("<parameter>" + it.next() + "</parameter>");
				}
				builder.append("</parameters>");
			}

			if (properties != null && properties.size() > 0) {
				builder.append("<properties>");
				Iterator<String> it = properties.iterator();
				while (it.hasNext()) {
					builder.append("<property>" + it.next() + "</property>");
				}
				builder.append("</properties>");
			}
			builder.append("</Component>");
			return builder.toString();
		} else
			return null;
	}

	public Element fillElement(Document doc) {
		Element element = doc.createElement(COMPONENT_ELEMENT);
		element.setAttribute(NAME_ATTR, name);
		if (parameters != null && parameters.size() > 0) {
			Element parametersEl = doc.createElement(PARAMETERS_EL);
			Iterator<String> it = parameters.iterator();
			while (it.hasNext()) {
				Element param = doc.createElement(PARAMETER_EL);
				param.setTextContent(it.next());
				parametersEl.appendChild(param);
			}
			element.appendChild(parametersEl);
		}
		if (properties != null && properties.size() > 0) {
			Element propertiesEl = doc.createElement(PROPERTIES_EL);
			Iterator<String> it = parameters.iterator();
			while (it.hasNext()) {
				Element param = doc.createElement(PROPERTY_EL);
				param.setTextContent(it.next());
				propertiesEl.appendChild(param);
			}
			element.appendChild(propertiesEl);
		}
		return element;
	}

	public int compareTo(T5Component o) {

		return this.name.compareTo(o.name);
	}

	/**
	 * Two T5Component are equal if their name is the same.
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof T5Component) {
			if (((T5Component) obj).getName() != null) {
				return ((T5Component) obj).name.equalsIgnoreCase(this.name);
			} else
				return false;
		} else
			return super.equals(obj);
	}

}
